package com.fy.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fy.common.constants.Constants;
import com.fy.common.constants.MessageConstant;
import com.fy.ex.ConditionException;
import com.fy.ex.handler.ExceptionHandler;
import com.fy.mapper.FileInfoMapper;
import com.fy.mapper.FileShareMapper;
import com.fy.mapper.UserMapper;
import com.fy.pojo.dto.file.DownLoadCodeDTO;
import com.fy.pojo.dto.fileshare.ShareSessionDTO;
import com.fy.pojo.dto.fileshare.ShowShareFileQueryDTO;
import com.fy.pojo.entity.FileInfo;
import com.fy.pojo.entity.FileShare;
import com.fy.pojo.entity.User;
import com.fy.pojo.enums.FileDelFlagEnums;
import com.fy.pojo.enums.FileDelTypeEnums;
import com.fy.pojo.enums.FileFolderTypeEnums;
import com.fy.pojo.vo.file.FileShareResultVO;
import com.fy.pojo.vo.file.FoloderVO;
import com.fy.pojo.vo.file.PageResultData;
import com.fy.pojo.vo.share.ShareFileVO;
import com.fy.pojo.vo.user.LoginUserVO;
import com.fy.pojo.vo.user.UserSpaceVO;
import com.fy.service.ShowShareService;
import com.fy.utils.DateFormatter;
import com.fy.utils.RedisUtils;
import com.fy.utils.StringTools;
import com.fy.utils.result.PageResult;
import com.fy.utils.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpSession;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;

import static com.fy.utils.DateFormatter.formatter;

@Slf4j
@Service
public class ShowShareServiceImpl implements ShowShareService {

    @Autowired
    private FileShareMapper fileShareMapper;

    @Autowired
    private FileInfoMapper fileInfoMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisUtils redisUtils;

    /**
     * 获取接收文件用户信息
     *
     * @param shareId
     * @return
     */
    @Override
    public Result getShareInfo(String shareId, HttpSession httpSession) {
        LoginUserVO loginUserVO = (LoginUserVO) httpSession.getAttribute(Constants.SESSION_KEY);
        // 1. 查询分享信息
        FileShare fileShare = fileShareMapper.selectById(shareId);
        ExceptionHandler.throwIf(fileShare == null, "分享不存在");

        // 2. 查询用户信息
        User user = userMapper.selectById(fileShare.getUserId());
        FileInfo info = fileInfoMapper.selectById(fileShare.getFileId());
        ExceptionHandler.throwIf(user == null, "用户不存在");

        // 3. 构建返回对象
        ShareFileVO shareFileVO = new ShareFileVO();
        FileShareResultVO fileShareResultVO = fileShareMapper.getFileShareResult(shareId);

        // 4. 设置基本信息
        shareFileVO.setShareTime(fileShareResultVO.getShareTime());
        shareFileVO.setAvatar(user.getAvatar());
        shareFileVO.setFolderType(String.valueOf(info.getFolderType()));
        shareFileVO.setExpireTime(fileShareResultVO.getExpireTime());
        shareFileVO.setFileId(fileShareResultVO.getFileId());
        shareFileVO.setNickName(user.getUsername());
        shareFileVO.setUserId(String.valueOf(user.getUserId()));

        // 5. 查询文件信息
        FileInfo fileInfo = fileInfoMapper.selectById(fileShareResultVO.getFileId());
        if (fileInfo != null) {
            shareFileVO.setFileCover(fileInfo.getFileCover());
            shareFileVO.setFileName(fileInfo.getFileName());
            if (fileInfo.getFileType() == null) {
                shareFileVO.setFileType(null);
            }
            shareFileVO.setFilePath(fileInfo.getFilePath());
        }

        // 6. 设置登录状态
        shareFileVO.setIsLogin(loginUserVO != null);

        // 7. 检查是否是当前用户的分享
        if (loginUserVO != null) {
            Integer currentUserId = Math.toIntExact(loginUserVO.getId());
            log.debug("Comparing userIds: fileShare.getUserId()={}, currentUserId={}",
                    fileShare.getUserId(), currentUserId);
            shareFileVO.setCurrentUser(Objects.equals(fileShare.getUserId(), currentUserId));
        } else {
            log.debug("loginUserVO is null");
            shareFileVO.setCurrentUser(false);
        }

        if (httpSession.getAttribute(Constants.SHARE_CODE_SESSION) != null
                && Objects.equals(shareId, httpSession.getAttribute(Constants.SHARE_CODE_SESSION))) {
            shareFileVO.setIsChecked(true);
        } else {
            shareFileVO.setIsChecked(false);
        }

        return Result.success(shareFileVO);
    }

    /**
     * 校验分享码
     *
     * @param shareId
     * @param code
     * @return
     */
    @Override
    public ShareSessionDTO checkShareCode(HttpSession httpSession, String shareId, String code) {
        ShareSessionDTO shareSessionDTO = new ShareSessionDTO();
        shareSessionDTO.setShareId(shareId);
        String fileShareExpireTime = fileShareMapper.selectShareExpireTimeById(shareId);
        shareSessionDTO.setExpireTime(fileShareExpireTime);
        shareSessionDTO.setShareUserId(String.valueOf(fileShareMapper.selectById(shareId).getUserId()));
        shareSessionDTO.setFileId(fileShareMapper.selectById(shareId).getFileId());
        // 解析过期日期
        LocalDateTime expiryDate = LocalDateTime.parse(fileShareExpireTime, formatter);
        // 获取当前日期时间
        LocalDateTime now = LocalDateTime.now();
        // 比较当前日期和过期日期
        if (now.isAfter(expiryDate)) {
            throw new ConditionException(MessageConstant.SHARE_EXPIRE_ERROR);
        }
        if (!fileShareMapper.selectById(shareId).getCode().equals(code)) {
            throw new ConditionException(MessageConstant.SHARE_CODE_ERROR);
        }
        httpSession.setAttribute(Constants.SHARE_CODE_SESSION, shareId);
        httpSession.setMaxInactiveInterval(1 * 24 * 60 * 60);
        fileShareMapper.updateShowCountById(shareId);
        return shareSessionDTO;
    }

    /**
     * 提取分享文件
     *
     * @param fileQueryDTO
     * @return
     */
    @Override
    public PageResult loadFileList(HttpSession httpSession, ShowShareFileQueryDTO fileQueryDTO) {
        // 添加参数校验
        if (fileQueryDTO == null) {
            throw new ConditionException("查询参数不能为空");
        }

        String shareId = (String) httpSession.getAttribute(Constants.SHARE_CODE_SESSION);
        ExceptionHandler.throwIf(StrUtil.isBlank(shareId), "验证过期,请重新验证!");

        FileShare fs = fileShareMapper.selectById(shareId);
        ExceptionHandler.throwIf(fs == null, "分享不存在");

        LoginUserVO loginUserVO = (LoginUserVO) httpSession.getAttribute(Constants.SESSION_KEY);
        // 如果用户已登录，且是分享者本人，则不需要验证码
        if (loginUserVO != null) {
            int userId = fs.getUserId();
            int userSessionId = Math.toIntExact(loginUserVO.getId());
            if (userId != userSessionId) {
                ExceptionHandler.throwIf(StrUtil.isBlank(shareId), "验证过期,请重新验证!");
            }
        } else {
            // 未登录用户必须验证分享码
            ExceptionHandler.throwIf(StrUtil.isBlank(shareId), "验证过期,请重新验证!");
        }

        // 设置默认值
        long pageSize = fileQueryDTO.getPageSize() != null && !fileQueryDTO.getPageSize().isEmpty()
                ? Long.parseLong(fileQueryDTO.getPageSize())
                : 15L; // 默认每页15条

        long pageNo = fileQueryDTO.getPageNo() != null && !fileQueryDTO.getPageNo().isEmpty()
                ? Long.parseLong(fileQueryDTO.getPageNo())
                : 1L; // 默认第1页

        String fileShareId = fileQueryDTO.getShareId();
        ExceptionHandler.throwIf(StringUtils.isEmpty(fileShareId), "分享ID不能为空");

        String fileSharePid = fileQueryDTO.getFilePid();

        if ("0".equals(fileSharePid)) {

            FileShare fileShare = fileShareMapper.selectById(fileShareId);
            FileInfo fileInfo = fileInfoMapper.selectById(fileShare.getFileId());

            List<FileInfo> list1 = new ArrayList<>();
            list1.add(fileInfo);
            List<PageResultData> list2 = list1.stream()
                    .map(record -> {
                        PageResultData pageResultData = new PageResultData();
                        BeanUtils.copyProperties(record, pageResultData);
                        // 格式化 createTime 和 lastUpdateTime
                        if (record.getCreateTime() != null) {
                            pageResultData.setRecoveryTime(DateFormatter
                                    .getYMDhmsFormatterStringByCST(String.valueOf(record.getCreateTime())));
                        }
                        if (record.getLastUpdateTime() != null) {
                            pageResultData.setLastUpdateTime(DateFormatter
                                    .getYMDhmsFormatterStringByCST(String.valueOf(record.getLastUpdateTime())));
                        }
                        return pageResultData;
                    })
                    .collect(Collectors.toList());
            PageResult pageResult = new PageResult();
            pageResult.setTotalCount(pageSize);
            pageResult.setPageNo(pageNo);
            pageResult.setPageSize(pageSize);
            pageResult.setPageTotal(pageSize);
            pageResult.setList(list2);

            return pageResult;

        } else {

            IPage<FileInfo> page = new Page<>(pageNo, pageSize);
            // 构建查询条件
            QueryWrapper<FileInfo> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("file_pid", fileQueryDTO.getFilePid());

            fileInfoMapper.selectPage(page, queryWrapper);

            List<FileInfo> list1 = page.getRecords();
            List<PageResultData> list2 = list1.stream()
                    .map(record -> {
                        PageResultData pageResultData = new PageResultData();
                        BeanUtils.copyProperties(record, pageResultData);

                        // 格式化 createTime 和 lastUpdateTime
                        if (record.getCreateTime() != null) {
                            pageResultData.setRecoveryTime(DateFormatter
                                    .getYMDhmsFormatterStringByCST(String.valueOf(record.getCreateTime())));
                        }
                        if (record.getLastUpdateTime() != null) {
                            pageResultData.setLastUpdateTime(DateFormatter
                                    .getYMDhmsFormatterStringByCST(String.valueOf(record.getLastUpdateTime())));
                        }

                        return pageResultData;
                    })
                    .collect(Collectors.toList());
            PageResult pageResult = new PageResult();
            pageResult.setTotalCount(page.getTotal());
            pageResult.setPageNo(page.getCurrent());
            pageResult.setPageSize(page.getSize());
            pageResult.setPageTotal(page.getPages());
            pageResult.setList(list2);

            log.info("一共多少页: {}", page.getPages());
            log.info("当前页码: {}", page.getCurrent());
            log.info("每页显示数: {}", page.getSize());
            log.info("一共多少条数据: {}", page.getTotal());

            return pageResult;
        }
    }

    /**
     * 获取发现文件夹目录信息
     *
     * @param path
     * @return
     */
    @Override
    public List<FoloderVO> getFolderInfo(String path) {
        // 用/分割路径获取fileId
        String[] folderStr = path.split("/");

        List<FoloderVO> foloderVOList = new ArrayList<>();

        // 遍历并设置返回参数
        for (String str : folderStr) {
            FoloderVO foloderVO = new FoloderVO();
            foloderVO.setFileName(fileInfoMapper.selectById(str).getFileName());
            foloderVO.setFileId(str);
            foloderVOList.add(foloderVO);
        }

        return foloderVOList;
    }

    /**
     * 获取文件路径
     *
     * @param fileId
     * @return
     */
    @Override
    public FileInfo getFilePath(String fileId) {
        return fileInfoMapper.selectById(fileId);
    }

    /**
     * 创建分享文件下载链接
     *
     * @param fileId
     * @return
     */
    @Override
    public String createDownloadURL(String fileId) {
        FileInfo fileInfo = fileInfoMapper.selectById(fileId);
        String redisDownLoadKey = fileId + "DownLoadCODE";
        DownLoadCodeDTO dto = new DownLoadCodeDTO();
        dto.setFileName(fileInfo.getFileName());
        dto.setFilePath(fileInfo.getFilePath());
        redisUtils.setex(redisDownLoadKey, dto, 10);
        return redisDownLoadKey;
    }

    /**
     * 保存分享文件
     *
     * @param loginUserVO
     * @param shareId
     * @param shareFileIds
     * @param myFolderId
     */
    @Override
    @Transactional
    public void saveShare(LoginUserVO loginUserVO, String shareId, String shareFileIds, String myFolderId) {
        int userId = userMapper.selectUserIdByName(loginUserVO.getNickName());
        String[] split = shareFileIds.split(",");
        long fileSize = 0; // 用来统计排除文件夹以外的，所有文件的大小总和，后续加入本地网盘的用户的使用空间信息中

        for (int i = 0; i < split.length; i++) {
            FileInfo fileInfo = fileInfoMapper.selectById(split[i]);

            if (Objects.equals(fileInfo.getFolderType(), FileFolderTypeEnums.FILE.getType())) {
                // 如果是文件
                fileSize = fileSize + copyFile(fileInfo, loginUserVO, myFolderId);
            } else if (Objects.equals(fileInfo.getFolderType(), FileFolderTypeEnums.FOLDER.getType())) {
                // 如果是文件夹
                fileSize = fileSize + copyFolder(fileInfo, loginUserVO, myFolderId);
            }
        }
        redisUtils.delete(loginUserVO.getNickName() + "Space");

        // 更新用户的使用空间
        UserSpaceVO vo = userMapper.selectSpaceByUserName(loginUserVO.getNickName());
        long newUseSpace = vo.getUseSpace() + fileSize;
        userMapper.updateSpaceByUserId(userId, newUseSpace);

        UserSpaceVO userSpaceVO = new UserSpaceVO();
        userSpaceVO.setUseSpace(newUseSpace);
        userSpaceVO.setTotalSpace(vo.getTotalSpace());
        redisUtils.setex(loginUserVO.getNickName() + "Space", userSpaceVO, 20);
    }

    private long copyFile(FileInfo fileInfo, LoginUserVO loginUserVO, String myFolderId) {
        // 构建新文件名
        String codeEmailPart = StringTools.getEmailPrefix(loginUserVO.getUserId());
        // 构造新文件名称
        String newFileId = codeEmailPart + "ADD" + UUID.randomUUID().toString().substring(0, 6);

        long fileSize = fileInfo.getFileSize();
        fileInfo.setUserId(userMapper.selectUserIdByName(loginUserVO.getNickName()));
        fileInfo.setFileId(newFileId);

        fileInfo.setFilePid(myFolderId);

        fileInfoMapper.insert(fileInfo);
        return fileSize;
    }

    private long copyFolder(FileInfo folderInfo, LoginUserVO loginUserVO, String myFolderId) {
        // 构建新文件夹名
        String codeEmailPart = StringTools.getEmailPrefix(loginUserVO.getUserId());
        // 构造新文件夹名称
        String newFolderId = codeEmailPart + "ADD" + UUID.randomUUID().toString().substring(0, 6);
        String sourceParentId = folderInfo.getFileId();
        folderInfo.setUserId(userMapper.selectUserIdByName(loginUserVO.getNickName()));
        folderInfo.setFileId(newFolderId);

        folderInfo.setFilePid(myFolderId);

        fileInfoMapper.insert(folderInfo);

        // 递归处理子文件和子文件夹
        long fileSize = copyChildren(sourceParentId, newFolderId, loginUserVO);
        return fileSize;
    }

    private long copyChildren(String sourceParentId, String targetParentId, LoginUserVO loginUserVO) {
        long fileSize = 0L;
        LambdaQueryWrapper<FileInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FileInfo::getFilePid, sourceParentId);
        List<FileInfo> children = fileInfoMapper.selectList(wrapper);
        for (FileInfo child : children) {
            if (Objects.equals(child.getFolderType(), FileFolderTypeEnums.FILE.getType())) {
                // 如果是文件，直接复制
                fileSize = fileSize + copyFile(child, loginUserVO, targetParentId);
            } else if (Objects.equals(child.getFolderType(), FileFolderTypeEnums.FOLDER.getType())) {
                // 如果是文件夹，递归处理
                copyFolder(child, loginUserVO, targetParentId);
            }
        }
        return fileSize;
    }

    @Override
    public List<FileInfo> loadMyFolder(HttpSession httpSession, String filePid) {
        // 1. 获取当前登录用户
        LoginUserVO loginUserVO = (LoginUserVO) httpSession.getAttribute(Constants.SESSION_KEY);
        ExceptionHandler.throwIf(loginUserVO == null, MessageConstant.BUSINESS_ERROR);

        // 2. 构建查询条件
        LambdaQueryWrapper<FileInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FileInfo::getFilePid, filePid)
                .eq(FileInfo::getDelFlag, FileDelFlagEnums.USING.getFlag())
                .eq(FileInfo::getDelType, FileDelTypeEnums.USING.getFlag())
                .eq(FileInfo::getUserId, loginUserVO.getId())
                .eq(FileInfo::getFolderType, FileFolderTypeEnums.FOLDER.getType()); // 只查询文件夹
        List<FileInfo> fileInfoList = fileInfoMapper.selectList(wrapper);
        log.info("fileInfoList: {}", fileInfoList);
        // 3. 使用fileInfoMapper而不是fileShareMapper
        return fileInfoList;
    }
}
